package com.suxin.event.annotations;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.GenericApplicationListener;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.lang.reflect.Method;

/**
 * @author Tang
 * @classname ApplicationListenerMethodAdapter
 * @description [  ]
 * @date 2023/2/28 16:46
 */
public class TransactionalApplicationListenerMethodAdapter extends ApplicationListenerMethodAdapter {

    final TransactionalEventListener annotation;

    public TransactionalApplicationListenerMethodAdapter(Method method, String beanName, Class<?> clz) {
        super(method, beanName, clz);
        annotation = AnnotatedElementUtils.findMergedAnnotation(method, TransactionalEventListener.class);
    }

    @Override
    public boolean supportsEventType(ResolvableType eventType) {
        return true;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        // 存在事物
        if (TransactionSynchronizationManager.isSynchronizationActive() &&
                TransactionSynchronizationManager.isActualTransactionActive()) {
            // 注册事物回调
            TransactionSynchronizationAdapter transactionSynchronization = createTransactionSynchronization(event, annotation.phase());
            TransactionSynchronizationManager.registerSynchronization(transactionSynchronization);
        }else {
            // 事物不存在是否直接执行事物
            if (this.annotation.fallbackExecution()) {
                processEvent(event);
            }
        }
    }

    public TransactionSynchronizationAdapter createTransactionSynchronization(ApplicationEvent event, TransactionPhase phase) {
        return new TransactionSynchronizationEventAdapter(this,event,phase);
    }

    public static class TransactionSynchronizationEventAdapter extends TransactionSynchronizationAdapter{

        private final ApplicationListener<ApplicationEvent> applicationListener;

        private final ApplicationEvent event;

        private final TransactionPhase phase;

        public TransactionSynchronizationEventAdapter(ApplicationListener<ApplicationEvent> applicationListener,
                                                      ApplicationEvent event, TransactionPhase phase) {
            this.applicationListener = applicationListener;
            this.event = event;
            this.phase = phase;
        }

        @Override
        public void beforeCommit(boolean readOnly) {
            if (this.phase == TransactionPhase.BEFORE_COMMIT) {
                this.applicationListener.onApplicationEvent(event);
            }
        }

        @Override
        public void afterCommit() {
            if (this.phase == TransactionPhase.AFTER_COMMIT) {
                this.applicationListener.onApplicationEvent(event);
            }
        }

        @Override
        public void afterCompletion(int status) {
            if (this.phase == TransactionPhase.AFTER_COMPLETION) {
                this.applicationListener.onApplicationEvent(event);
            }
        }
    }

}